﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Text;
using Common;
using Controladores;
using Entidades;
using Entidades.jSON;
using Entidades.jSON.Sistema;
using Ionic.Zlib;
using Newtonsoft.Json;
using Web.Handlers.Data;
using Web.Helpers;
using Web.Helpers.Documents.Spreadsheets.Enums;
using Web.Helpers.jqGridHelpers;
using Web.Helpers.Documents.Spreadsheets;
using System.IO;
using Ionic.Zip;

namespace Web.Pages
{
    public class BasePage : System.Web.UI.Page
    {
        /// <summary>
        /// Logger instance
        /// </summary>
        //public static ILog Logger { get; set; }

        /// <summary>
        /// Entities stored in cache memory
        /// </summary>
        private static readonly Dictionary<Type, string> CachedEntities = new Dictionary<Type, string>()
        {
            { typeof (UsuarioCategoria), WellKnownKeys.Cache.CATEGORIAS_USUARIO },
            { typeof (GuionEstado), WellKnownKeys.Cache.ESTADOS_GUION },
            { typeof (PagoEstado), WellKnownKeys.Cache.ESTADOS_PAGO },
            { typeof (ReclamoEstado), WellKnownKeys.Cache.ESTADOS_RECLAMO },
            { typeof (PagoMedio), WellKnownKeys.Cache.MEDIOS_PAGO },
            { typeof (Proyecto), WellKnownKeys.Cache.PROYECTOS },
            { typeof (TipoCancion), WellKnownKeys.Cache.TIPOS_CANCION },
            { typeof (TipoDocumento), WellKnownKeys.Cache.TIPOS_DOCUMENTO },
            { typeof (ProyectoTipo), WellKnownKeys.Cache.TIPOS_PROYECTO },
            { typeof (UsuarioTipo), WellKnownKeys.Cache.TIPOS_USUARIO },
            { typeof (Usuario), WellKnownKeys.Cache.USUARIOS }
        };

        protected void Page_Load(object sender, EventArgs e)
        {
            //this.ConfigureLogger();

            this.Error += new System.EventHandler(this.Page_Error);
        }

        //private void ConfigureLogger()
        //{
        //    if (Logger != null)
        //        return;
        //    Logger = LogManager.GetLogger(Assembly.GetExecutingAssembly().GetTypes().First());
        //    log4net.Config.XmlConfigurator.Configure();
        //}

        public void Page_Error(object sender, EventArgs e)
        {
            var ex = HttpContext.Current.Server.GetLastError();
            LogException(ex);
        }

        // TODO => Do this the right way!
        public static void LogMessage(string message, string details = null)
        {
            new ControladorBase<Error>().GuardarEntidad(new Error()
            {
                FechaYHora = DateTime.Now,
                Message = message,
                ExceptionType = String.Empty,
                StackTrace = String.IsNullOrEmpty(details) ? String.Empty : details
            });               
        }
        public static void LogError(Exception ex)
        {
            LogException(ex);
        }

        private static void LogException(Exception exception)
        {
            try
            {
                //Logger.Error( String.Format("Source: {0}, Method: {1}, Exception Type: {2}, Message: {3}", exception.TargetSite.DeclaringType.FullName, exception.TargetSite.Name, exception.GetType(), exception.Message));

                // Get the last exception thrown
                //var ex = Server.GetLastError();
                //var exception = HttpContext.Current.Server.GetLastError();

                //Log
                var exceptionDetails = exception.GetExceptionDetails();
                new ControladorBase<Error>().GuardarEntidad(new Error()
                {
                    FechaYHora = DateTime.Now,
                    //Message = exception.Message,
                    Message = exceptionDetails,
                    ExceptionType = exception.GetType().ToString(),
                    StackTrace = exception.StackTrace
                });            

                // Clear the error from the server
                //Server.ClearError();
                HttpContext.Current.Server.ClearError();
            }
            catch (Exception)
            {
                //throw;
            }
        }

        #region ViewState
        public static T GetViewStateValue<T>(string key)
        {
            return (T)((BasePage)HttpContext.Current.CurrentHandler).ViewState[key];
        }
        public static void SetViewStateValue(string key, object value)
        {
            ((BasePage)HttpContext.Current.CurrentHandler).ViewState[key] = value;
        }
        #endregion

        #region Constants

        //public const string PARAMS_ID_PROYECTO = Common.WellKnownKeys.Page.Parameters.ID_PROYECTO;

        #endregion

        #region Web Methods

        #region GENERAL

        [WebMethod]
        public static string activarEntidad(string entidad, int id, bool activa = true)
        {
            var mensaje = string.Empty;
            var resultado = false;
            //object valor = null;
            try
            {
                switch (entidad.ToLower())
                {
                    case "guion":
                        resultado = ActivarEntidad<Guion>(id, activa);
                        break;
                    case "proyecto":
                        resultado = ActivarEntidad<Proyecto>(id, activa);
                        break;
                    case "usuario":
                        resultado = ActivarEntidad<Usuario>(id, activa);
                        break;
                }
                mensaje     = resultado ? "Los datos fueron habilitados exitosamente." : "Hubo un error al intentar habilitar los datos.";
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar habilitar los datos." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, null);
        }

        #endregion

        #region Sesion

        /// <summary>
        /// Obtiene el usuario logueado
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerUsuarioLogueado()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                var usuario = SessionHelper.GetCurrentUser();
                if (usuario != null)
                {
                    valor = usuario;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido recuperar la información del Usuario logueado.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar habilitar los datos del Proyecto." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, null);
        }

        /// <summary>
        /// Abre una nueva sesión
        /// </summary>
        /// <param name="nombreUsuario"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        [WebMethod]
        public static string abrirSesion(string nombreUsuario, string password)
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var uc = new UsuarioControlador();
                var usuario = uc.ObtenerPorUsuarioYPassword(nombreUsuario, password);
                if ( usuario != null)
                {
                    //Helpers.WebHelper.Session.Set(WellKnownKeys.Session.CURRENT_USER, usuario);
                    //valor       = new UsuarioInfo(usuario);
                    var usuarioInfo = new UsuarioInfo(usuario);
                    valor       = usuarioInfo;
                    mensaje     = usuario.Nombre + " ha iniciado sesión.";
                    resultado   = true;
                    Helpers.WebHelper.Session.Set(WellKnownKeys.Session.CURRENT_USER, usuarioInfo);
                }
                else
                {
                    mensaje = "Los datos son incorrectos.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje += Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Abre una nueva sesión
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string cerrarSesion()
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var uc = new UsuarioControlador();
                var usuario = SessionHelper.GetCurrentUser();
                if ( usuario != null)
                {
                    Helpers.WebHelper.Session.Set(WellKnownKeys.Session.CURRENT_USER, null);
                    mensaje = "Sesión cerrada";
                    resultado = true;
                }
                else
                {
                    mensaje = "La sesión no pudo ser cerrada.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Redirige a la página inicial del Usuario
        /// </summary>
        /// <param name="idTipoUsuario"></param>
        /// <param name="idCategoriaUsuario"></param>
        [WebMethod]
        public static string cargarPaginaInicial(int idTipoUsuario, int idCategoriaUsuario)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                mensaje     = "OK";
                resultado   = true;
                valor       = Helpers.SecurityHelper.GetDefaultPage(idTipoUsuario, idCategoriaUsuario);
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar cargar la página inicial." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Usuario
        
        /// <summary>
        /// Devuelve un Usuario, según su Id
        /// </summary>
        /// <param name="idUsuario"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerUsuario(int idUsuario)
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                Usuario usuario = new ControladorBase<Usuario>().ObtenerEntidad( idUsuario );
                if ( usuario != null )
                {
                    valor = new UsuarioInfo( usuario );
                    resultado = true;
                }
                else
                {
                    mensaje = "No se han podido obtener los datos del Usuario.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener los datos del Usuario." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Devuelva una lista de todos los Usuarios
        /// </summary>
        /// <param name="pageSize"></param>
        /// <param name="currentPage"></param>
        /// <param name="sortColumn"></param>
        /// <param name="sortOrder"></param>
        /// <param name="search"></param>
        /// <param name="searchFilter"></param>
        /// <param name="colModel"></param>
        /// <param name="isExport"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerUsuarios(int pageSize, int currentPage, string sortColumn, string sortOrder, string search, string searchFilter, string colModel, bool isExport)
        {
            var jSON = string.Empty;
            try
            {
                var gridData = new GridDataHelper<Usuario>().GetData(searchFilter, colModel, currentPage, pageSize, sortOrder, sortColumn);

                #region Construir set de datos

                var lista = from Usuario item in gridData.Data
                    select new object[]
                    {
                        item.Id.ToString(),
                        item.Activo,
                        BasePage.CrearBoton(WellKnownKeys.Grid.Actions.ACTIVAR, "Usuario", item.Id,
                            item.Activo
                                ? WellKnownKeys.Images.Icons.HABILITADO
                                : WellKnownKeys.Images.Icons.DESHABILITADO),
                        BasePage.CrearBoton(WellKnownKeys.Grid.Actions.EDITAR, "Usuario", item.Id,
                            WellKnownKeys.Images.Icons.EDITAR),
                        item.Activo
                            ? BasePage.CrearBoton(WellKnownKeys.Grid.Actions.ELIMINAR, "Usuario", item.Id,
                                WellKnownKeys.Images.Icons.ELIMINAR)
                            : "",
                        item.Tipo.Id.ToString(),
                        item.Tipo.Nombre,
                        //item.Categoria.Id.ToString(),
                        //item.Categoria.Nombre,
                        item.Nombre,
                        item.Apellido,
                        item.Categoria.Id,
                        item.Categoria.Nombre
                    };

                var jqGridData = new jqGridData(gridData.TotalRecords, gridData.TotalPages, gridData.CurrentPage, lista);

                #endregion

                jSON = Formatter.JSON<jqGridData>.Serialize(jqGridData);
            }
            catch (Exception ex)
            {
                LogError(ex);
                throw;
            }
            return jSON;
        }

        /// <summary>
        /// Devuelva una lista de todos los Usuarios, de un Tipo determinado
        /// </summary>
        /// <param name="tipo"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaUsuariosPorTipo(string tipo)
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var usuarios     = new UsuarioControlador().ObtenerUsuariosPorTipo(tipo);
                var usuariosInfo = new List<ListaInfo>();
                if (usuarios != null)
                {
                    foreach(var usuario in usuarios)
                    {
                        var listaInfo = new ListaInfo
                        {
                            Id          = usuario.Id,
                            Texto       = usuario.Nombre + " " + usuario.Apellido,
                            Habilitado  = usuario.Activo,
                            Valor       = new UsuarioInfo(usuario)
                        };
                        usuariosInfo.Add( listaInfo );
                    }
                    valor = usuariosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Usuarios del tipo " + tipo.ToString();
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Devuelva una lista de todos los Usuarios, de una Categoría determinada
        /// </summary>
        /// <param name="categoria"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaUsuariosPorCategoria(string categoria)
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                var usuarios     = new UsuarioControlador().ObtenerUsuariosPorCategoria(categoria);
                var usuariosInfo = new List<ListaInfo>();
                if (usuarios != null)
                {
                    foreach(var usuario in usuarios)
                    {
                        var listaInfo = new ListaInfo
                        {
                            Id          = usuario.Id,
                            Texto       = usuario.Nombre + " " + usuario.Apellido,
                            Habilitado  = usuario.Activo,
                            Valor       = new UsuarioInfo(usuario)
                        };
                        usuariosInfo.Add( listaInfo );
                    }
                    valor = usuariosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se han podido obtener los Usuarios.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Elimina los datos de un Usuario
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [WebMethod]
        public static string eliminarUsuario(string id)
        {
            string mensaje  = string.Empty;
            bool resultado  = false;
            object valor    = null;
            try
            {
                resultado = ActivarEntidad<Usuario>( Convert.ToInt32(id), false);
                mensaje = resultado ? "Los datos del Usuario fueron eliminados exitosamente." : "Hubo un error al intentar eliminar los datos del Usuario.";
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar eliminar los datos del Usuario." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Parámetro

        /// <summary>
        /// Devuelve los Parámetros del sistema
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerParametros()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                Parametro parametro = new ControladorBase<Parametro>().ObtenerEntidad();
                if ( parametro != null )
                {
                    valor = new ParametroInfo( parametro );
                    resultado = true;
                }
                else
                {
                    mensaje = "No se han podido recuperar los Parámetros del sistema.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar recuperar los Parámetros del sistema." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Proyecto

        /// <summary>
        /// Deuelve una lista de todos los Proyectos
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaProyectos()
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var proyectos       = new ControladorBase<Proyecto>().ObtenerEntidades();
                var proyectosInfo   = new List<ListaInfo>();
                if (proyectos != null)
                {
                    foreach(var proyecto in proyectos)
                    {
                        var listaInfo = new ListaInfo
                        {
                            Id          = proyecto.Id,
                            Texto       = proyecto.Nombre,
                            Habilitado  = proyecto.Activo,
                            Valor       = new ProyectoInfo(proyecto)
                        };
                        proyectosInfo.Add( listaInfo );
                    }
                    valor = proyectosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Proyectos.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Elimina los datos de un Proyecto
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [WebMethod]
        public static string eliminarProyecto(string id)
        {
            var mensaje  = string.Empty;
            var resultado  = false;
            object valor    = null;
            try
            {
                //var controladorBase = new ControladorBase<Proyecto>();
                //var proyecto = controladorBase.ObtenerEntidad( Convert.ToInt32(id) );
                //    proyecto.Activo = false;
                //resultado = controladorBase.GuardarEntidad( proyecto );
                resultado = ActivarEntidad<Proyecto>( Convert.ToInt32(id), false);
                mensaje =  resultado ? "Los datos del Proyecto fueron eliminados exitosamente." : "Hubo un error al intentar eliminar los datos del Proyecto.";
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar eliminar los datos del Proyecto." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Guion

        /// <summary>
        /// Devuelve un Guión, según su Id
        /// </summary>
        /// <param name="idGuion"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerGuion(int idGuion)
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                Guion guion = new ControladorBase<Guion>().ObtenerEntidad( idGuion );
                if ( guion != null )
                {
                    valor = new GuionInfo( guion );
                    resultado = true;
                }
                else
                {
                    mensaje = "No se han podido obtener los datos del Guión.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener los datos del Guión." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Elimina los datos de un Guión
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [WebMethod]
        public static string eliminarGuion(int id)
        {
            var mensaje  = string.Empty;
            var resultado  = false;
            object valor    = null;
            try
            {
                var controladorGuion = new ControladorBase<Guion>();

                var guion = controladorGuion.ObtenerEntidad( id );
                if (guion == null)
                    throw new Exception("No existe el Guión solicitado.");

                var currentUser = SessionHelper.GetCurrentUser();
                var canDelete = BusinessRulesHelper.Guion.CanDelete(guion, currentUser);
                if (!canDelete)
                {
                    mensaje = "No tiene permisos para realizar esta acción.";
                }
                else
                {
                    guion.Activo = false;
                    resultado = controladorGuion.GuardarEntidad( guion );

                    var controladorGuionImportacion = new ControladorBase<GuionImportacion>();
                    var guionImportacion = controladorGuionImportacion.ObtenerEntidad(x => x.Guion.Id == guion.Id);
                    if (guionImportacion != null)
                    {
                        guionImportacion.Activo = false;
                        resultado = controladorGuionImportacion.GuardarEntidad( guionImportacion );
                    }

                    resultado = true;
                    mensaje = "Los datos del Guión fueron eliminados exitosamente.";
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar eliminar los datos del Guión." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        [WebMethod]
        public static string obtenerGuionesPendientesDePago(int idProyecto)
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var guionesInfo = new List<ListaInfo>();
                var guiones = new GuionControlador().ObtenerGuionesPendientesDePago(idProyecto, WellKnownKeys.Entities.TiposUsuario.ACTOR.Id);
                if (guiones.IsNotNull())
                {
                    guionesInfo.AddRange(
                        guiones.Select(
                            guion =>
                                new ListaInfo()
                                {
                                    Id = guion.Id,
                                    Texto = String.Format("Ep. {0} - {1}", guion.Episodio, guion.Titulo)
                                }));
                    valor = guionesInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se han podido obtener el listado de Guiones.";
                    resultado = false;
                }   
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener el Detalle de la Planilla de Pago." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Tipo Cancion

        /// <summary>
        /// Deuelve una lista de todos los Tipos de Canción
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaTiposCancion()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                List<TipoCancion> tipos     = new ControladorBase<TipoCancion>().ObtenerEntidades();
                List<ListaInfo> tiposInfo   = new List<ListaInfo>();
                if (tipos != null)
                {
                    foreach(TipoCancion tipo in tipos)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = tipo.Id;
                                    listaInfo.Texto = tipo.Nombre;
                                    listaInfo.Valor = new TipoCancionInfo(tipo);

                        tiposInfo.Add( listaInfo );
                    }
                    valor = tiposInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Tipos de Canción";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Estados Guion

        /// <summary>
        /// Devuelve una Lista de todos los Estados de un Guión
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaEstadosGuion()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                var estados = new ControladorBase<GuionEstado>().ObtenerEntidades();
                if (estados != null)
                {
                    // estados = estados.OrderBy(x => x.Id).ToList();
                    estados = estados.OrderBy(x => x.Orden).ToList();
                    valor = estados.Select(estado => new ListaInfo
                    {
                        Id = estado.Id,
                        Texto = estado.Nombre,
                        Valor = new GuionEstadoInfo(estado)
                    }).ToList();
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Estados de un Guión.";
                    resultado = false;
                }
            }
            catch (Exception)
            {
                throw;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Estados Pago

        /// <summary>
        /// Devuelve una Lista de todos los Estados de un Pago
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaEstadosPago()
        {
            var mensaje = string.Empty;
            var resultado = false;
            object valor = null;
            try
            {
                var estados = new ControladorBase<PagoEstado>().ObtenerEntidades();
                if (estados != null)
                {
                    valor = estados.Select(estado => new ListaInfo
                    {
                        Id = estado.Id,
                        Texto = estado.Nombre,
                        Valor = new PagoEstadoInfo(estado)
                    }).ToList();
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Estados de un Pago.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Medios Pago

        /// <summary>
        /// Devuelve una Lista de todos los Medios de un Pago
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaMediosPago()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                List<PagoMedio> medios = new ControladorBase<PagoMedio>().ObtenerEntidades();
                List<ListaInfo> mediosInfo   = new List<ListaInfo>();
                if (medios != null)
                {
                    foreach(PagoMedio medio in medios)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = medio.Id;
                                    listaInfo.Texto = medio.Nombre;
                                    listaInfo.Valor = new PagoMedioInfo(medio);

                        mediosInfo.Add( listaInfo );
                    }
                    valor = mediosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Medios de Pago.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Tipo Usuario

        /// <summary>
        /// Deuelve una lista de todos los Tipos de Usuario
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaTiposUsuario()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                ControladorBase<UsuarioTipo> cb = new ControladorBase<UsuarioTipo>();
                List<UsuarioTipo> tipos = cb.ObtenerEntidades();
                List<ListaInfo> tiposInfo   = new List<ListaInfo>();
                if (tipos != null)
                {
                    foreach(UsuarioTipo tipo in tipos)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = tipo.Id;
                                    listaInfo.Texto = tipo.Nombre;
                                    listaInfo.Valor = new UsuarioTipoInfo(tipo);

                        tiposInfo.Add( listaInfo );
                    }
                    valor = tiposInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Tipos de Usuario";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Categoría Usuario

        /// <summary>
        /// Deuelve una lista de todos las Categorias de Usuario
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaCategoriasUsuario()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                List<UsuarioCategoria> categorias   = new ControladorBase<UsuarioCategoria>().ObtenerEntidades();
                List<ListaInfo> categoriasInfo      = new List<ListaInfo>();
                if (categorias != null)
                {
                    foreach(UsuarioCategoria categoria in categorias)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = categoria.Id;
                                    listaInfo.Texto = categoria.Nombre;
                                    listaInfo.Valor = new UsuarioCategoriaInfo(categoria);

                        categoriasInfo.Add( listaInfo );
                    }
                    valor = categoriasInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener las Categorías de Usuario.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Estados Reclamo

        /// <summary>
        /// Devuelve una Lista de todos los Estados de un Reclamo
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaEstadosReclamo()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                List<ReclamoEstado> estados = new ControladorBase<ReclamoEstado>().ObtenerEntidades();
                List<ListaInfo> estadosInfo   = new List<ListaInfo>();
                if (estados != null)
                {
                    foreach(ReclamoEstado estado in estados)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = estado.Id;
                                    listaInfo.Texto = estado.Nombre;
                                    listaInfo.Valor = new ReclamoEstadoInfo(estado);

                        estadosInfo.Add( listaInfo );
                    }
                    valor = estadosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Estados de un Reclamo.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Reclamo

        /// <summary>
        /// Envía un Reclamo
        /// </summary>
        /// <param name="idPago"></param>
        /// <param name="idEmisor"></param>
        /// <param name="descripcion"></param>
        /// <returns></returns>
        [WebMethod]
        public static string enviarReclamo(int idPago, int idEmisor, string descripcion)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var reclamo = new Reclamo
                {
                    Estado  = new ControladorBase<ReclamoEstado>().ObtenerEntidad(WellKnownKeys.Entities.EstadosReclamo.SIN_ATENDER.Id),
                    Fecha   = DateTime.Now,
                    Pago    = new ControladorBase<Pago>().ObtenerEntidad(idPago)
                };

                var reclamoItem = new ReclamoItem
                {
                    Descripcion = descripcion,
                    Fecha = reclamo.Fecha,
                    Reclamo = reclamo,
                    Emisor = new ControladorBase<Usuario>().ObtenerEntidad(idEmisor)
                };

                reclamo.Items = new List<ReclamoItem> { reclamoItem };

                #region Envio Mail
                var parametro       = new ControladorBase<Parametro>().ObtenerEntidad();
                var emailReclamos   = parametro.EmailReclamos;
                var destinatarios = MailHelper.CreateRecipientsList(emailReclamos, "Reclamos");
                resultado = MailHelper.EnviarMailReclamo(destinatarios, MostrarNombreCompleto(reclamo.Pago.Proveedor) + " ha enviado un reclamo." , reclamo.Pago.Guion.Titulo + " - " + reclamo.Pago.Guion.Episodio, descripcion, reclamo.Fecha, reclamo.Pago.Proveedor.Nombre + " " + reclamo.Pago.Proveedor.Apellido);
                #endregion

                if ( resultado )
                {
                    resultado = new ControladorBase<Reclamo>().GuardarEntidad( reclamo );
                    if ( resultado )
                        mensaje = "El reclamo fue enviado exitosamente.";
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                var detalle = ex.Message;
                if ( ex.InnerException != null )
                    detalle = detalle + Environment.NewLine + ex.InnerException.Message;
                mensaje = "Hubo un error al intentar enviar el Reclamo." + Environment.NewLine + "Detalle: " + Environment.NewLine + detalle;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Envía la respuesta a un Reclamo
        /// </summary>
        /// <param name="idReclamo"></param>
        /// <param name="idEmisor"></param>
        /// <param name="idEstado"></param>
        /// <param name="descripcion"></param>
        /// <returns></returns>
        [WebMethod]
        public static string enviarRespuestaReclamo(int idReclamo, int idEmisor, int idEstado, string descripcion)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var controladorReclamo = new ControladorBase<Reclamo>();

                var reclamo = controladorReclamo.ObtenerEntidad( idReclamo );

                var esProveedor = true;
                var usuarioLogueado = SessionHelper.GetCurrentUser();
                if ( BasePage.ValidarPermisosAdmin(usuarioLogueado) )
                {
                    reclamo.Estado = new ControladorBase<ReclamoEstado>().ObtenerEntidad( idEstado );
                    esProveedor = false;
                }

                reclamo.Items.Add
                (
                    new ReclamoItem
                    {
                        Descripcion = descripcion,
                        Fecha = DateTime.Now,
                        Reclamo = reclamo,
                        Emisor = new ControladorBase<Usuario>().ObtenerEntidad(idEmisor)
                    }
                );

                #region Envio Mail
                var parametro = new ControladorBase<Parametro>().ObtenerEntidad();

                var emailDestinatario    = string.Empty;
                var nombreDestinatario   = string.Empty;
                if ( esProveedor )
                {
                    emailDestinatario       = parametro.EmailReclamos;
                    nombreDestinatario      = "Administrador";
                }
                else
                {
                    emailDestinatario       = reclamo.Pago.Proveedor.Email;
                    nombreDestinatario      = "Proveedor - " + MostrarNombreCompleto( reclamo.Pago.Proveedor );
                }

                var asunto = String.Format("Respuesta del reclamo del {0}", reclamo.Fecha.ToShortDateString());
                var destinatarios = MailHelper.CreateRecipientsList(emailDestinatario, nombreDestinatario);
                resultado = MailHelper.EnviarMailReclamo(destinatarios, asunto, reclamo.Pago.Guion.Titulo + " - " + reclamo.Pago.Guion.Episodio, descripcion, reclamo.Fecha, MostrarNombreCompleto(reclamo.Pago.Proveedor));
                #endregion

                if ( resultado )
                {
                    controladorReclamo.GuardarEntidad( reclamo );
                    mensaje = "El mensaje fue enviado exitosamente.";
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar enviar la respuesta al Reclamo." + Environment.NewLine + "Detalle: " + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Devuelve la info de un Reclamo
        /// </summary>
        /// <param name="idReclamo"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerReclamo(int idReclamo)
        {
            var mensaje  = string.Empty;
            var resultado  = false;
            object valor    = null;
            try
            {
                var reclamo = new ControladorBase<Reclamo>().ObtenerEntidad( idReclamo );
                if ( reclamo != null )
                {
                    valor       = new ReclamoInfo( reclamo );
                    resultado   = true;
                }
                else
                {
                    throw new Exception( "No se ha podido obtener los datos del Reclamo." );
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener los datos del Reclamo." + Environment.NewLine + ex.Message;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Devuelve una lista con todos los Reclamos, según un Estado
        /// </summary>
        /// <param name="estadoReclamo"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerReclamosPorEstado(string estadoReclamo)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var sb = new StringBuilder();
                QueryFilter.BuildFilter(sb, "Estado.Nombre", estadoReclamo, typeof(String), QueryFilter.EqualityOperators.Equal);
                var reclamos = new ControladorBase<Reclamo>().ObtenerEntidades(null, sb.ToString());
                if (reclamos != null)
                {
                    var reclamosInfo = reclamos.Select(reclamo => new ListaInfo
                    {
                        Id = reclamo.Id, Texto = reclamo.Nombre, Valor = new ReclamoInfo(reclamo)
                    }).ToList();
                    valor = reclamosInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Reclamos '" + estadoReclamo + "'.";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        #region Tipo Documento

        /// <summary>
        /// Deuelve una lista de todos los Tipos de Documento
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerListaTiposDocumento()
        {
            string mensaje = string.Empty;
            bool resultado = false;
            object valor = null;
            try
            {
                List<TipoDocumento> tipos     = new ControladorBase<TipoDocumento>().ObtenerEntidades();
                List<ListaInfo> tiposInfo   = new List<ListaInfo>();
                if (tipos != null)
                {
                    foreach(TipoDocumento tipo in tipos)
                    {
                        ListaInfo   listaInfo       = new ListaInfo();
                                    listaInfo.Id    = tipo.Id;
                                    listaInfo.Texto = tipo.Nombre;
                                    listaInfo.Valor = new TipoDocumentoInfo(tipo);

                        tiposInfo.Add( listaInfo );
                    }
                    valor = tiposInfo;
                    resultado = true;
                }
                else
                {
                    mensaje = "No se ha podido obtener los Tipos de Documento";
                    resultado = false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #endregion

        [WebMethod]
        public static string generarPlanilla(string infoPlanilla, string infoPlanillaItems)
        {
            var mensaje = String.Empty;
            var resultado = false;
            object valor = null;
            try
            {                                
                var planillaInfo = JsonConvert.DeserializeObject<PlanillaInfo>(infoPlanilla);

                switch ( planillaInfo.TipoPlanilla )
                {
                    case TiposPlanilla.Actores:
                    case TiposPlanilla.Staff:
                        var planillaPagoInfo = Helpers.PlanillasHelper.DeserializarPlanillaDePagoInfo(infoPlanilla, infoPlanillaItems);
                        var pagosActualizados = BasePage.ActualizarPagos(planillaPagoInfo);
                        var idsPagosActualizadosOk = pagosActualizados.Where(x => x.Value).Select(x => x.Key).ToArray();
                        planillaPagoInfo.Items = planillaPagoInfo.Items.Where(x => idsPagosActualizadosOk.Contains(x.IdPago) ).ToList();
                        mensaje = String.Format("Planilla generada" + "<br /><br />" + "Pagos actualizados: {0}/{1}", idsPagosActualizadosOk.Length, pagosActualizados.Count);
                        break;

                    case TiposPlanilla.Credito:
                        // TODO => WTF ???
                        //var planillaCreditosInfo = Helpers.PlanillasHelper.DeserializarPlanillaDeCreditosInfo(infoPlanilla, infoPlanillaItems);
                        mensaje = "Planilla generada" + "<br />";
                        break;
                }

                var fileNamePlanilla = Helpers.PlanillasHelper.GenerarPlanilla( infoPlanilla, infoPlanillaItems );

                // TODO => make this config key a Constant
                var appHost = ConfigurationManager.AppSettings["appHost"];

                if (!String.IsNullOrEmpty(appHost))
                {
                    fileNamePlanilla = fileNamePlanilla.Replace( Helpers.FileHelper.GetServerRoot(), appHost );
                }

                valor = fileNamePlanilla;
                resultado = true;
            }
            catch (Exception ex)
            {
                //throw ex;
                LogError(ex);
                mensaje = "Hubo un error al intentar generar la Planilla.";
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        [WebMethod]
        public static string continueImporProcess(int idTranslator, string firstName, string lastName)
        {
            var respuestaInfo = default(RespuestaInfo);
            try
            {
                var context = Helpers.WebHelper.GetCurrentContext();

                var importProject = ScriptHelper.GetImportCurrentState(context, String.Empty);

                importProject.Data.IdTranslator = idTranslator;
                importProject.Data.TranslatorFirstName = firstName;
                importProject.Data.TranslatorLastName = lastName;
                
                ScriptHelper.SaveImportCurrentState(context, importProject, ImportStep.ReadyForImport);

                respuestaInfo = ScriptHelper.ContinueImportProcess(importProject, context);
            }
            catch (Exception ex)
            {
                //throw ex;
                LogError(ex);

                respuestaInfo = ScriptHelper.GetResponseInfoWithExceptionData(ex);
            }

            return SessionHelper.BuildResponse(respuestaInfo);
        }

        [WebMethod]
        public static string obtenerTransicionAutorizacion(int idTransicionAutorizacion)
        {
            var respuestaInfo = default(RespuestaInfo);
            var mensaje = String.Empty;
            var valor = default(object);
            var resultado = false;
            try
            {
                var controlador = new ControladorBase<GuionAutorizacionTransicion>();

                var transicionAutorizacion = controlador.ObtenerEntidad(x => x.Id == idTransicionAutorizacion);
                if (transicionAutorizacion != null)
                {
                    var autorizacionTransicionInfo = new GuionAutorizacionTransicionInfo(transicionAutorizacion);

                    mensaje = "Autorización obtenida exitosamente.";
                    resultado = true;
                    valor = autorizacionTransicionInfo;

                    respuestaInfo = new RespuestaInfo(resultado, mensaje, valor);
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                LogError(ex);

                respuestaInfo = new RespuestaInfo(resultado, mensaje, valor);
            }
            return SessionHelper.BuildResponse(respuestaInfo);
        }

        [WebMethod]
        public static string resolverAutorizacion(GuionAutorizacionTransicionInfo autorizacionTransicionInfo)
        {
            var respuestaInfo = default(RespuestaInfo);
            try
            {
                var controladorGuion = new ControladorBase<Guion>();
                var controladorUsuario = new ControladorBase<Usuario>();

                var currentUser = Helpers.SessionHelper.GetCurrentUser();
                var usuarioActual = controladorUsuario.ObtenerEntidad(x => x.Id == currentUser.Id);
                var usuarioNotificado = controladorUsuario.ObtenerEntidad(x => x.Id == autorizacionTransicionInfo.IdUsuarioNotificado);
                var fechaActual = DateTime.Now;

                var guion = controladorGuion.ObtenerEntidad(x => x.Id == autorizacionTransicionInfo.IdGuion);

                var aprobada = false;
                if (autorizacionTransicionInfo.Aprobada.HasValue)
                    aprobada = autorizacionTransicionInfo.Aprobada.Value;

                GuionControlador.ActualizarTransicionDeAutorizacion(guion, autorizacionTransicionInfo.Id, aprobada, autorizacionTransicionInfo.Comentarios, fechaActual, usuarioActual, usuarioNotificado);

                var idAutorizacion = guion.TransicionDeAutorizaciones.Last().Autorizacion.Id;

                switch (idAutorizacion)
                {
                    case WellKnownKeys.Entities.AutorizacionesGuion.TRADUCCION.Id:
                        if (aprobada)
                            GuionControlador.AgregarTransicionDeAutorizacion(guion, WellKnownKeys.Entities.AutorizacionesGuion.PRODUCCION.Id, fechaActual, usuarioActual.Id);
                        break;
                    case WellKnownKeys.Entities.AutorizacionesGuion.PRODUCCION.Id:
                        break;
                }

                if (controladorGuion.GuardarEntidad(guion))
                {
                    respuestaInfo = new RespuestaInfo(true, "Autorización resuelta exitosamente.", autorizacionTransicionInfo);

                    if (usuarioNotificado != null)
                    {
                        var destinatarios = MailHelper.CreateRecipientsList(usuarioNotificado.Email, usuarioNotificado.Descriptor);

                        Helpers.MailHelper.EnviarMailSolicitudAutorizacionGuion
                            (
                                destinatarios,
                                String.Format("{0} - Ep. {1}", guion.Titulo, guion.Episodio),
                                guion.TransicionDeAutorizaciones.Last().Autorizacion.Nombre,
                                String.Format("{0}, {1}", currentUser.Apellido, currentUser.Nombre),
                                usuarioNotificado.Descriptor
                            );
                    }
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                LogError(ex);

                respuestaInfo = new RespuestaInfo(false, "Ocurrió un error al intentar resolver la Autorización. Detalle: " + ex.Message, null);
            }
            
            return SessionHelper.BuildResponse(respuestaInfo);
        }

        #endregion

        #region Helpers

        /// <summary>
        /// Genera el html para crear un hipervínculo con forma de botón, para disparar un método javascript.
        /// </summary>
        /// <param name="accion"></param>
        /// <param name="entidad"></param>
        /// <param name="idEntidad"></param>
        /// <param name="icono"></param>
        /// <returns></returns>
        public static string CrearBoton(string accion, string entidad, int idEntidad, string icono = "")
        {
            return "<a id='btn" + accion + entidad + "_" + idEntidad + "' class='btn" + accion + entidad + "' href='javascript:void(0);' ><img src='" + icono + "' /></a>";
        }

        /// <summary>
        /// Genera el html para crear un hipervínculo con forma de botón, para disparar un método javascript.
        /// </summary>
        /// <param name="accion"></param>
        /// <param name="entidad"></param>
        /// <param name="idEntidad"></param>
        /// <param name="icono"></param>
        /// <returns></returns>
        public static string CrearBotonConEstilo(string accion, string entidad, int idEntidad, string icono, string texto = null)
        {
            string btnClass = "botonAccion";
            return  "<div id='btn" + accion + entidad + "_" + idEntidad + "' class='btn" + accion + entidad + " " + btnClass + "' >" + 
                    "<img src='" + icono + "' />" +
                    "<label>" + ( !string.IsNullOrEmpty(texto) ? texto : string.Empty ) + "</label>" +
                    "</div>";
        }

        ///// <summary>
        ///// Genera el html para crear un hipervínculo , para disparar un método javascript.
        ///// </summary>
        ///// <param name="accion"></param>
        ///// <param name="entidad"></param>
        ///// <param name="idEntidad"></param>
        ///// <returns></returns>
        //public static string CrearLink(string metodo, int idEntidad, string texto)
        //{
        //    return "<a href='javascript:" + metodo + "(" + idEntidad + ")' class='grid-link' >" +  texto + "</a>";
        //}

        /// <summary>
        /// Genera el html para crear un hipervínculo , para disparar un método javascript.
        /// </summary>
        /// <param name="accion"></param>
        /// <param name="entidad"></param>
        /// <param name="idEntidad"></param>
        /// <param name="texto"></param>
        /// <returns></returns>
        public static string CrearLink(string metodo, int idEntidad, string texto)
        {
            return "<a id='btn" + metodo + "_" + idEntidad + "' class='btn" + metodo + " grid-link' href='javascript:void(0);' title='' >" + texto + "</a>";
        }

        /// <summary>
        /// Muestra el nombre completo (Apellido + ", " + Apellido)
        /// </summary>
        /// <param name="entidad"></param>
        /// <returns></returns>
        public static string MostrarNombreCompleto(Usuario usuario)
        {
            return string.Format("{0}, {1}", usuario.Apellido, usuario.Nombre);
        }

        /// <summary>
        /// Compara el el Tipo de un Usuario (por defecto, el Usuario logueado) contra un Tipo dado
        /// </summary>
        /// <param name="idTpoUsuario"></param>
        /// <param name="usuario"></param>
        /// <returns></returns>
        public static bool ValidarTipoUsuario(int idTpoUsuario, UsuarioInfo usuario = null)
        {
            var _usuario = usuario ?? SessionHelper.GetCurrentUser();
            if (_usuario != null)
                return _usuario.IdTipo == idTpoUsuario;
            else
                return false;
        }

        public static Usuario GetUsuario(Guion guion, int idTipoUsuario)
        {
            var usuario = default(Usuario);
            switch (idTipoUsuario)
            {
                case WellKnownKeys.Entities.TiposUsuario.ADAPTADOR.Id:
                    if (guion.Adaptador != null)
                        usuario = guion.Adaptador;
                    break;
                case WellKnownKeys.Entities.TiposUsuario.DIRECTOR.Id:
                    if (guion.Director != null)
                        usuario = guion.Director;
                    break;
                case WellKnownKeys.Entities.TiposUsuario.MEZCLADOR.Id:
                    if (guion.Mezclador != null)
                        usuario = guion.Mezclador;
                    break;
                case WellKnownKeys.Entities.TiposUsuario.TRADUCTOR.Id:
                    if (guion.Traductor != null)
                        usuario = guion.Traductor;
                    break;
                case WellKnownKeys.Entities.TiposUsuario.TEMPORIZADOR.Id:
                    if (guion.Temporizador != null)
                        usuario = guion.Temporizador;
                    break;
            }
            return usuario;
        }

        public static bool ValidarPermisosAdmin(UsuarioInfo usuario = null)
        {
            var currentUser = usuario ?? SessionHelper.GetCurrentUser();

            if ( currentUser.IsNull() )
                return false;

            return currentUser.IdTipo == WellKnownKeys.Entities.TiposUsuario.ADMINISTRADOR.Id ||
                   currentUser.IdTipo == WellKnownKeys.Entities.TiposUsuario.PRODUCCION.Id;
        }

        /// <summary>
        /// Devuelve el primer valor en caso de ser no nulo. En su defecto, devuelve el segundo.
        /// </summary>
        /// <param name="valorActual"></param>
        /// <param name="valorDefault"></param>
        /// <returns></returns>
        public static object UsarValorNoNulo(object valorActual, object valorDefault)
        {
            return valorActual ?? valorDefault;
        }

        #endregion

        #region Grid

        public class Grid<T> where T:Entidad
        {
            public jqGridData GetGridData(string searchFilter, string colModel, int currentPage, int pageSize, string sortOrder, string sortColumn, Func<IList<T>, IEnumerable<object[]>> buildDataRowsFunc)
            {
                var gridData = new GridDataHelper<T>().GetData(searchFilter, colModel, currentPage, pageSize, sortOrder, sortColumn);
                var dataRows = buildDataRowsFunc(gridData.Data);
                var jqGridData = new jqGridData(gridData.TotalRecords, gridData.TotalPages, gridData.CurrentPage, dataRows);

                return jqGridData;
            }

            public jqGridData GetGridData(string sp, Dictionary<string, object> parameters, int currentPage, int pageSize, Func<IList<T>, IEnumerable<object[]>> buildDataRowsFunc)
            {
                var sp_count        = String.Format("{0}_count", sp);
                var totalRecords    = new ControladorBase<Entidades.Calculado.TotalRecords>.StoredProcedure().ObtenerTotalRecords(sp_count, parameters);
                var data            = new ControladorBase<T>.StoredProcedure().GetList(sp, pageSize, currentPage, parameters);
                var gridData        = new GridDataHelper().GetPaginationData(totalRecords, currentPage, pageSize);
                var dataRows        = buildDataRowsFunc(data);
                var jqGridData      = new jqGridData(gridData.TotalRecords, gridData.TotalPages, gridData.CurrentPage, dataRows);

                return jqGridData;
            }
        }

        #endregion

        #region Entities

        #region Reclamos

        public class Reclamos //: CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos(string estado)
            {
                var reclamosInfo = new List<ListaInfo>();
                try
                {
                    var reclamos = new ControladorBase<Reclamo>().ObtenerEntidades(x => x.Estado.Nombre.ToLower() == estado.ToLower());
                    if (reclamos.IsNotNull())
                        reclamosInfo.AddRange(reclamos.Select(reclamo => new ListaInfo { Id = reclamo.Id, Texto = reclamo.Nombre }));
                }
                catch (Exception)
                {
                    throw;
                }
                return reclamosInfo;
            }
        }

        public class EstadosReclamo : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<ReclamoEstado, ReclamoEstadoInfo>();
            }
        }

        #endregion

        #region Usuarios

        public class Usuarios : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<Usuario, UsuarioInfo>
                    (
                        x =>
                        x.Tipo.Id != WellKnownKeys.Entities.TiposUsuario.ADMINISTRADOR.Id &&
                        x.Tipo.Id != WellKnownKeys.Entities.TiposUsuario.PRODUCCION.Id &&
                        x.Activo
                    );
            }

            public static bool GuardarUsuario(ControladorBase<Usuario> controlador, Usuario usuario)
            {
                return GuardarEntidad<Usuario>(controlador, usuario);
            }

            //public static bool EliminarUsuario(ControladorBase<Usuario> controlador, Usuario usuario)
            //{
            //    return EliminarEntidad<Usuario>(controlador, usuario, key);
            //}
        }

        public class TiposUsuario : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<UsuarioTipo, UsuarioTipoInfo>();
            }
        }

        public class CategoriasUsuario : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<UsuarioCategoria, UsuarioCategoriaInfo>();
            }
        }

        #endregion

        public class Proyectos : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                var proyectosInfo = ObtenerTodos<Proyecto, ProyectoInfo>();
                return proyectosInfo.OrderByDescending(x => x.Id).ToList();
            }
            public static List<ListaInfo> ObtenerTodosPendientesDePago()
            {
                var proyectosInfo = ObtenerTodos<Proyecto, ProyectoInfo>();
                return proyectosInfo.OrderByDescending(x => x.Id).ToList();
            }
            public static List<ListaInfo> ObtenerTodosPagados()
            {
                var proyectosInfo = ObtenerTodos<Proyecto, ProyectoInfo>();
                return proyectosInfo.OrderByDescending(x => x.Id).ToList();
            }

            public static bool GuardarProyecto(ControladorBase<Proyecto> controlador, Proyecto proyecto)
            {
                return GuardarEntidad<Proyecto>(controlador, proyecto);
            }
        }

        public class TiposProyecto : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<ProyectoTipo, ProyectoTipoInfo>();
            }
        }

        public class EstadosGuion : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                //return ObtenerTodos<GuionEstado, GuionEstadoInfo>();
                return ObtenerTodos<GuionEstado, GuionEstadoInfo>(null, x => x.Id);
            }
        }

        public class AutorizacionesGuion : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<GuionAutorizacion, GuionAutorizacionInfo>();
            }
        }

        public class MediosPago : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<PagoMedio, PagoMedioInfo>();
            }
        }

        public class EstadosPago : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<PagoEstado, PagoEstadoInfo>();
            }
        }

        public class TiposCancion : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<TipoCancion, TipoCancionInfo>();
            }
        }

        public class TiposDocumento : CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos()
            {
                return ObtenerTodos<TipoDocumento, TipoDocumentoInfo>();
            }
        }

        private static bool GuardarEntidad<T>(ControladorBase<T> controlador, T entidad) where T:Entidad
        {
            controlador.GuardarEntidad(entidad);

            Cache.Update<T>();

            return true;
        }

        private static bool EliminarEntidad<T>(ControladorBase<T> controlador, T entidad, string key) where T:Entidad
        {
            controlador.EliminarEntidad(entidad);
            Helpers.WebHelper.Cache.RemoveValue(key);
            return true;
        }

        private static bool ActivarEntidad<T>(int id, bool activa = true) where T:Entidad
        {
            var resultado = false;
            try
            {
                var controlador = new ControladorBase<T>();
                var entidad = controlador.ObtenerEntidad(id);
                if ( entidad.IsNotNull() )
                {
                    entidad.Activo = activa;
                    resultado = GuardarEntidad(controlador, entidad);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return resultado;
        }

        #endregion

        #region Parametros

        public class Parametros : CacheEntity
        {
            public static ParametroInfo Obtener()
            {
                var listaInfo = ObtenerTodos<Parametro, ParametroInfo>().FirstOrDefault();
                return listaInfo != null ? (ParametroInfo)listaInfo.Valor : default(ParametroInfo);
            }
        }

        #endregion

        public string ConvertBoolToString(bool value)
        {
            return value == true ? "1" : "0";
        }

        public class StoredProcedure<T> where T : Entidad
        {
            public T GetObject(string sp, Dictionary<string, object> parameters = null)
            {
                return new ControladorBase<T>.StoredProcedure().GetObject(sp, parameters);
            }
            public IList<T> GetList(string sp, Dictionary<string, object> parameters = null)
            {
                return new ControladorBase<T>.StoredProcedure().GetList(sp, parameters);
            }
        }

        #region Private Methods

        #region Caché
        public class CacheEntity
        {
            public static List<ListaInfo> ObtenerTodos<T, TModel>(Func<T, bool> filterCriteria = null, Func<T, object> sortCriteria = null ) where T:Entidad
            {
                List<ListaInfo> entidades;
                try
                {
                    entidades = Cache.Get<T, List<ListaInfo>>();
                    if (entidades.IsNull())
                    {
                        //var controlador = new ControladorBase<T>();
                        //var datos = criteria.IsNotNull() ? controlador.ObtenerEntidades(criteria) : controlador.ObtenerEntidades();
                        if ( filterCriteria.IsNull() )
                            filterCriteria = x => x.Activo;
                        var datos = new ControladorBase<T>().ObtenerEntidades(filterCriteria);
                        if (datos.IsNotNull())
                        {
                            //datos = datos.OrderBy(x => x.Descriptor).ToList();
                            if (sortCriteria == null )
                                sortCriteria = x => x.Descriptor;
                            datos = datos.OrderBy(sortCriteria).ToList();

                            entidades = datos.Select
                                        (
                                            x =>
                                                new ListaInfo
                                                {
                                                    Id          = x.Id,
                                                    Texto       = x.Descriptor,
                                                    Habilitado  = x.Activo,
                                                    Valor       = x.GetModel<T, TModel>()
                                                }
                                        ).ToList();
                            Cache.Update<T>(entidades);
                        }
                    }
                }
                catch (Exception)
                {
                    throw;
                }
                return entidades;
            }        
        }
        public new class Cache
        {
            public static TReturnType Get<T, TReturnType>() where T: Entidad
            {
                var key = GetKey<T>();
                return Helpers.WebHelper.Cache.GetValue<TReturnType>(key);
            }
            public static T Get<T>(string key)
            {
                return Helpers.WebHelper.Cache.GetValue<T>(key);
            }
            public static void Update<T>(object data = null) where T: Entidad
            {
                var key = GetKey<T>();
                if ( key.IsNotNull() && key.Length > 0 )
                {
                    if (data.IsNotNull())
                        Helpers.WebHelper.Cache.SetValue<object>(key, data);
                    else
                        Helpers.WebHelper.Cache.RemoveValue(key);
                }
            }
            private static KeyValuePair<Type, string> GetCacheKeyValuePairFromDictionary<T>() where T:Entidad
            {
                return CachedEntities.GetKeyValuePair(typeof (T));
            }
            public static string GetKey<T>() where T:Entidad
            {
                var keyValuePair = GetCacheKeyValuePairFromDictionary<T>();
                if ( keyValuePair.IsNotNull() && keyValuePair.Key.IsNotNull() )
                    return keyValuePair.Value;
                else
                    return null;
            }
        }
        #endregion
        
        #endregion

        public static Dictionary<int, bool> ActualizarPagos(PlanillaDePagoInfo planillaInfo)
        {
            var pagosActualizados = new Dictionary<int, bool>();
            try
            {
                var controladorPago         = new ControladorBase<Pago>();
                var controladorPagoEstado   = new ControladorBase<PagoEstado>();
                var controladorPagoMedio    = new ControladorBase<PagoMedio>();

                var medioPago   = controladorPagoMedio.ObtenerEntidad(planillaInfo.IdMedioPago);
                var estadoPago  = controladorPagoEstado.ObtenerEntidad(WellKnownKeys.Entities.EstadosPago.PAGADO.Id);
                var fechaPago   = DateTime.Now;
                var proyecto    = planillaInfo.Proyecto;

                var numerosCelularProveedores = new Dictionary<int, string>();

                #region Actualización de Pagos
                foreach (var pagoInfo in planillaInfo.Items)
                {
                    #region Por cada Pago
                    try
                    {
                        var isPagoActualizado = false;

                        var pago = controladorPago.ObtenerEntidad(pagoInfo.IdPago);
                        if (pago.IsNotNull())
                        {
                            pago.Estado     = estadoPago;
                            pago.FechaPago  = fechaPago;
                            pago.MedioPago  = medioPago;

                            if (pago.Proveedor.Celular.IsNotNull() && pago.Proveedor.Celular.Length > 0)
                            {
                                // TODO => improve this
                                if ( pago.Proveedor.Celular.Length == 12 )
                                {
                                    if ( !numerosCelularProveedores.ContainsKey(pago.Proveedor.Id) )
                                        numerosCelularProveedores.Add( pago.Proveedor.Id, pago.Proveedor.Celular );
                                }
                            }

                            pago.UsuarioUltimaModificacion = new ControladorBase<Usuario>().ObtenerEntidad( Helpers.SessionHelper.GetCurrentUser().Id );
                            pago.FechaUltimaModificacion = DateTime.Now;

                            isPagoActualizado = controladorPago.GuardarEntidad(pago);
                        }
                        
                        if ( !pagosActualizados.ContainsKey( pagoInfo.IdPago ) )
                            pagosActualizados.Add( pago.Id, isPagoActualizado );

                        var sent = MailHelper.EnviarMailNotificacionGuionPagado(pago, MailHelper.OnEnvioMailCompletado);
                    }
                    catch (Exception ex)
                    {
                        BasePage.LogError(ex);
                        try
                        {
                            if ( !pagosActualizados.ContainsKey( pagoInfo.IdPago ) )
                                pagosActualizados.Add( pagoInfo.IdPago, false );
                        }
                        catch (Exception ex2)
                        {
                            BasePage.LogError(ex2);
                            throw;
                        }
                    }
                    #endregion
                }

                if ( numerosCelularProveedores.Count > 0 )
                    MailHelper.EnviarMailSms( numerosCelularProveedores.Values.ToList(), proyecto, medioPago.Nombre );

                #endregion
            }
            catch (Exception ex)
            {
                BasePage.LogError(ex);
                throw;
            }
            return pagosActualizados;
        }

        public static MemoryStream CreateZipFile(string[] fileNames, string directory = null)
        {
            var outputStream = new MemoryStream();
            try
            {
                using (var zip = new ZipFile())
                {
                    zip.CompressionLevel = CompressionLevel.BestCompression;
                    zip.AddFiles( fileNames, directory );
                    zip.Save( outputStream );                    
                }
            }
            catch (System.IO.FileNotFoundException)
            {
                throw;
            }
            catch (Exception)
            {
                throw;
            }
            return outputStream;
        }

        public static void StreamFileToBrowser(string fileName, byte[] fileBytes)
        {
            var context = HttpContext.Current;
            context.Response.Clear();
            context.Response.ClearHeaders();
            context.Response.ClearContent();
            context.Response.BufferOutput = false; // for large files
            context.Response.AppendHeader("content-length", fileBytes.Length.ToString());
            context.Response.ContentType = "application/octet-stream"; //GetMimeTypeByFileName(fileName);
            context.Response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
            context.Response.BinaryWrite(fileBytes);

            // use this instead of response.end to avoid thread aborted exception (known issue):
            // http://support.microsoft.com/kb/312629/EN-US
            context.ApplicationInstance.CompleteRequest();
        }

        /// <summary>
        /// Gets the MIME type of the file name specified based on the file name's
        /// extension.  If the file's extension is unknown, returns "octet-stream"
        /// generic for streaming file bytes.
        /// </summary>
        /// <param name="sFileName">The name of the file for which the MIME type
        /// refers to.</param>
        public static string GetMimeTypeByFileName(string sFileName)
        {
            var sMime = "application/octet-stream";
            var sExtension = System.IO.Path.GetExtension(sFileName);
            if (!string.IsNullOrEmpty(sExtension))
            {
                sExtension = sExtension.Replace(".", "");
                sExtension = sExtension.ToLower();
                if (sExtension == "xls" || sExtension == "xlsx")
                {
                    sMime = "application/ms-excel";
                }
                else if (sExtension == "doc" || sExtension == "docx")
                {
                    sMime = "application/msword";
                }
                else if (sExtension == "ppt" || sExtension == "pptx")
                {
                    sMime = "application/ms-powerpoint";
                }
                else if (sExtension == "rtf")
                {
                    sMime = "application/rtf";
                }
                else if (sExtension == "zip")
                {
                    sMime = "application/zip";
                }
                else if (sExtension == "mp3")
                {
                    sMime = "audio/mpeg";
                }
                else if (sExtension == "bmp")
                {
                    sMime = "image/bmp";
                }
                else if (sExtension == "gif")
                {
                    sMime = "image/gif";
                }
                else if (sExtension == "jpg" || sExtension == "jpeg")
                {
                    sMime = "image/jpeg";
                }
                else if (sExtension == "png")
                {
                    sMime = "image/png";
                }
                else if (sExtension == "tiff" || sExtension == "tif")
                {
                    sMime = "image/tiff";
                }
                else if (sExtension == "txt")
                {
                    sMime = "text/plain";
                }
            }
            return sMime;
        }
    }
}